package com.geeaks.generator.controller;

import java.io.File;
import java.net.URL;
import java.util.List;
import java.util.Objects;
import java.util.ResourceBundle;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.mybatis.generator.config.ColumnOverride;
import org.mybatis.generator.config.IgnoredColumn;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.geeaks.generator.enums.EnumFXMLPage;
import com.geeaks.generator.enums.EnumTemplate;
import com.geeaks.generator.generator.Generator;
import com.geeaks.generator.model.DatabaseConfigBo;
import com.geeaks.generator.model.GenerateConfigBo;
import com.geeaks.generator.model.TemplateBo;
import com.geeaks.generator.model.UITableColumnBo;
import com.geeaks.generator.util.ConfigHelper;
import com.geeaks.generator.util.DbUtil;
import com.geeaks.generator.util.MyStringUtils;
import com.geeaks.generator.view.AlertUtil;
import com.geeaks.generator.view.UIProgressCallback;
import com.google.common.base.Strings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.control.cell.TextFieldTreeCell;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.stage.DirectoryChooser;
import javafx.util.Callback;

/**
 * @Description: 主界面控制器
 * @author gaoxiang
 * @date 2019-04-13 11:22:54
 */
public class MainUIController extends BaseFXController {
	
	private static final Logger logger = LoggerFactory.getLogger(MainUIController.class);
	
	/**
	 * @Fields connectionLabel : 数据库连接按钮
	 */
	@FXML
	private Label connectionLabel;
	
	/**
	 * @Fields packageName : 包名
	 */
	@FXML
	private TextField packageNameField;
	
	/**
	 * @Fields tableNameField : 表名
	 */
	@FXML
	private TextField tableNameField;
	
	/**
	 * @Fields domainObjectNameField : 实体类名(选填)
	 */
	@FXML
	private TextField entityField;
	
	/**
	 * @Fields targetField : 输出目标路径
	 */
	@FXML
	private TextField targetField;
	
	/**
	 * @Fields authorField : 作者
	 */ 
	@FXML
	private TextField authorField;
	
	/**
	 * @Fields configField : 选择的模板
	 */
	@FXML
	private TextField templateField;
	
	/**
	 * @Fields leftDBTree : 左侧库表列表
	 */
	@FXML
	private TreeView<String> leftDBTree;
	
	// Current selected databaseConfig
	private DatabaseConfigBo selectedDatabaseConfig;
	
	// Current selected tableName
	private String tableName;
	
	private List<IgnoredColumn> ignoredColumns;
	
	private List<ColumnOverride> columnOverrides;
	
	private TemplateBo templateBo;
	
	@SuppressWarnings("unchecked")
	@Override
	public void initialize(URL location, ResourceBundle resources) {
		// 新建连接按钮
		ImageView dbImage = new ImageView("icons/computer.png");
		dbImage.setFitHeight(40);
		dbImage.setFitWidth(40);
		connectionLabel.setGraphic(dbImage);
		connectionLabel.setOnMouseClicked(event -> {
			NewConnectionController controller = (NewConnectionController) loadFXMLPage("新建数据库连接", EnumFXMLPage.new_connection, false);
			controller.setMainUIController(this);
			controller.showDialogStage();
		});
		leftDBTree.setShowRoot(false);
		leftDBTree.setRoot(new TreeItem<>());
		Callback<TreeView<String>, TreeCell<String>> defaultCellFactory = TextFieldTreeCell.forTreeView();
		leftDBTree.setCellFactory((TreeView<String> tv) -> {
			TreeCell<String> cell = defaultCellFactory.call(tv);
			cell.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
				int level = leftDBTree.getTreeItemLevel(cell.getTreeItem());
				TreeCell<String> treeCell = (TreeCell<String>) event.getSource();
				TreeItem<String> treeItem = treeCell.getTreeItem();
				if (level == 1) {
					final ContextMenu contextMenu = new ContextMenu();
					MenuItem item1 = new MenuItem("关闭连接");
					item1.setOnAction(event1 -> {
						treeItem.getChildren().clear();
					});
					MenuItem item2 = new MenuItem("删除连接");
					item2.setOnAction(event1 -> {
						DatabaseConfigBo selectedConfig = (DatabaseConfigBo) treeItem.getGraphic().getUserData();
						try {
							ConfigHelper.deleteDatabaseConfig(selectedConfig.getName());
							this.loadLeftDBTree();
						} catch (Exception e) {
							AlertUtil.showErrorAlert("Delete connection failed! Reason: " + e.getMessage());
						}
					});
					contextMenu.getItems().addAll(item1, item2);
					cell.setContextMenu(contextMenu);
				}
				// 双击展开 库表列表
				if (event.getClickCount() == 2) {
					treeItem.setExpanded(true);
					if (level == 1) {
						DatabaseConfigBo selectedConfig = (DatabaseConfigBo) treeItem.getGraphic().getUserData();
						try {
							List<String> tables = DbUtil.getTableNames(selectedConfig);
							if (tables != null && tables.size() > 0) {
								ObservableList<TreeItem<String>> children = cell.getTreeItem().getChildren();
								children.clear();
								for (String tableName : tables) {
									TreeItem<String> newTreeItem = new TreeItem<>();
									ImageView imageView = new ImageView("icons/table.png");
									imageView.setFitHeight(16);
									imageView.setFitWidth(16);
									newTreeItem.setGraphic(imageView);
									newTreeItem.setValue(tableName);
									children.add(newTreeItem);
								}
							}
						} catch (Exception e) {
							logger.error(e.getMessage(), e);
							AlertUtil.showErrorAlert(e.getMessage());
						}
					} else if (level == 2) { // left DB tree level3
						String tableName = treeCell.getTreeItem().getValue();
						selectedDatabaseConfig = (DatabaseConfigBo) treeItem.getParent().getGraphic().getUserData();
						this.tableName = tableName;
						tableNameField.setText(tableName);
						entityField.setText(MyStringUtils.dbStringToCamelStyle(tableName));
					}
				}
			});
			return cell;
		});
		loadLeftDBTree();
	}
	
	void loadLeftDBTree() {
		TreeItem<String> rootTreeItem = leftDBTree.getRoot();
		rootTreeItem.getChildren().clear();
		List<DatabaseConfigBo> dbConfigs = null;
		try {
			dbConfigs = ConfigHelper.loadDatabaseConfig();
			for (DatabaseConfigBo dbConfig : dbConfigs) {
				TreeItem<String> treeItem = new TreeItem<>();
				treeItem.setValue(dbConfig.getName());
				ImageView dbImage = new ImageView("icons/computer.png");
				dbImage.setFitHeight(16);
				dbImage.setFitWidth(16);
				dbImage.setUserData(dbConfig);
				treeItem.setGraphic(dbImage);
				rootTreeItem.getChildren().add(treeItem);
			}
		} catch (Exception e) {
			logger.error("connect db failed, reason: {}", e);
			AlertUtil.showErrorAlert(e.getMessage() + "\n" + ExceptionUtils.getStackTrace(e));
		}
	}
	
	@FXML
	public void chooseProjectFolder() {
		DirectoryChooser directoryChooser = new DirectoryChooser();
		File selectedFolder = directoryChooser.showDialog(getPrimaryStage());
		if (selectedFolder != null) {
			targetField.setText(selectedFolder.getAbsolutePath());
		}
	}
	
	@FXML
	public void generateCode() {
		if (tableName == null) {
			AlertUtil.showWarnAlert("请先在左侧选择数据库表");
			return;
		}
		String result = validateConfig();
		if (result != null) {
			AlertUtil.showErrorAlert(result);
			return;
		}
		GenerateConfigBo generatorConfig = getGenerateConfig();
		generatorConfig.setIgnoredColumns(ignoredColumns);
		generatorConfig.setColumnOverrides(columnOverrides);
		
		UIProgressCallback alert = new UIProgressCallback(Alert.AlertType.INFORMATION);
		try {
			String templateCode = Objects.isNull(templateBo)?null:templateBo.getTemplateCode();
			Generator generator = EnumTemplate.nameOf(templateCode).getGenerator();
			generator.setGeneratorConfig(generatorConfig);
			generator.setDatabaseConfig(selectedDatabaseConfig);
			String msg = generator.generate();
			if (Strings.isNullOrEmpty(msg)) {
				alert.done();
			} else {
				alert.progressText.setValue(msg);
			}
			alert.show();
		} catch (Exception e) {
			AlertUtil.showErrorAlert(e.getMessage());
		}
	}
	
	@FXML
	public void generatePorject() {
		String result = validateConfig();
		if (result != null) {
			AlertUtil.showErrorAlert(result);
			return;
		}
		UIProgressCallback alert = new UIProgressCallback(Alert.AlertType.INFORMATION);
		try {
			String templateCode = Objects.isNull(templateBo)?null:templateBo.getTemplateCode();
			Generator generator = EnumTemplate.nameOf(templateCode).getGenerator();
			List<String> tableNames = DbUtil.getTableNames(selectedDatabaseConfig);
			for(String tableName : tableNames) {
				GenerateConfigBo generatorConfig = getGenerateConfig();
				generatorConfig.setTableNameField(tableName);
				generatorConfig.setEntityField(MyStringUtils.dbStringToCamelStyle(tableName));
				generator.setGeneratorConfig(generatorConfig);
				generator.setDatabaseConfig(selectedDatabaseConfig);
				String msg = generator.generate();
				if (Strings.isNullOrEmpty(msg)) {
				} else {
					alert.progressText.setValue(msg);
					break;
				}
			}
			alert.done();
			alert.show();
		} catch (Exception e) {
			e.printStackTrace();
			AlertUtil.showErrorAlert(e.getMessage());
		}
	}
	
	private String validateConfig() {
		if (StringUtils.isAnyEmpty(packageNameField.getText())) {
			return "包名不能为空";
		}
		if (StringUtils.isAnyEmpty(authorField.getText())) {
			return "作者不能为空";
		}
		if (StringUtils.isEmpty(targetField.getText())) {
			return "目标目录不能为空";
		}
		return null;
	}
	
	/**
	 * @Description: 获取用户的设置
	 * @author gaoxiang
	 * @date 2019-04-13 19:58:11
	 */
	public GenerateConfigBo getGenerateConfig() {
		GenerateConfigBo generatorConfig = new GenerateConfigBo();
		generatorConfig.setTableNameField(tableNameField.getText());
		generatorConfig.setEntityField(entityField.getText());
		generatorConfig.setPackageNameField(packageNameField.getText());
		generatorConfig.setTargetField(targetField.getText());
		generatorConfig.setAuthor(authorField.getText());
		String templateCode = Objects.isNull(templateBo)?null:templateBo.getTemplateCode();
		EnumTemplate template = EnumTemplate.nameOf(templateCode);
		generatorConfig.setTemplatePath(template.path);
		return generatorConfig;
	}
	
	@FXML
	public void openTableColumnCustomizationPage() {
		if (tableName == null) {
			AlertUtil.showWarnAlert("请先在左侧选择数据库表");
			return;
		}
		SelectTableColumnController controller = (SelectTableColumnController) loadFXMLPage("定制列", EnumFXMLPage.select_table_column, true);
		controller.setMainUIController(this);
		try {
			if (!tableName.equals(controller.getTableName())) {
				List<UITableColumnBo> tableColumns = DbUtil.getTableColumns(selectedDatabaseConfig, tableName);
				controller.setColumnList(FXCollections.observableList(tableColumns));
				controller.setTableName(tableName);
			}
			controller.showDialogStage();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			AlertUtil.showErrorAlert(e.getMessage());
		}
	}
	
	@FXML
	public void openTemplate() {
		try {
			TemplateController controller = (TemplateController) loadFXMLPage("", EnumFXMLPage.template, false);
			List<TemplateBo> templateList = EnumTemplate.getList();
			controller.setTemplate(FXCollections.observableList(templateList));
			controller.setMainUIController(this);
			controller.showDialogStage();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			AlertUtil.showErrorAlert(e.getMessage());
		}
	}
	
	public void setIgnoredColumns(List<IgnoredColumn> ignoredColumns) {
		this.ignoredColumns = ignoredColumns;
	}
	
	public void setColumnOverrides(List<ColumnOverride> columnOverrides) {
		this.columnOverrides = columnOverrides;
	}
	
	public void setTemplateBo(TemplateBo templateBo) {
		this.templateBo = templateBo;
	}
	
	public void setTemplateValue(String value) {
		templateField.setText(value);
	}
}
